package com.kaifamiao.nio;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * ByteBuffer内部实现:
 *      final byte[] hb; // 对于非直接缓存区来说，该数组就是真正存放数据的地方
 *      // Invariants: mark <= position <= limit <= capacity
 *      private int mark = -1; // 标记位置
 *      private int position = 0; // 当前位置，通过 position() 来获取，通过 position(int) 来设置
 *      private int limit; // 限制位置，通过 limit() 来获取，通过 limit(int) 来设置
 *      private int capacity; // 缓冲区的容量
 */
public class BufferTest {

    public static void main(String[] args) {

        // ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        System.out.println( buffer );
        // 判断是否是"直接缓冲区"
        System.out.println( buffer.isDirect() );
        show(buffer);

        // 在当前位置添加一个字符(占2个字节)
        buffer.putChar('芳');
        show(buffer);

        buffer.putChar(':');
        show(buffer);

        // 在当前位置添加一批字节 (数组里有多少字节就添加多少字节)
        buffer.put( "最近上课睡的怎么样?".getBytes(StandardCharsets.UTF_8));
        show(buffer);

        final int current = buffer.position(); // return position;
        // 以当前位置为限制位置
        buffer.limit( current ); // limit = newLimit;
        show(buffer);

        // 若超出 limit 位置进行读写操作则会抛出 BufferOverflowException
        // buffer.putChar('俊');
        // buffer.getChar();

        // 重新回到缓冲区起始位置
        buffer.position(0); // position = newPosition
        show(buffer);

        // 从当前位置读取两个字节并重构成char值
        char ch = buffer.getChar(); // 读取两个字节并重构成char值
        System.out.println( ch );
        show(buffer);

        // 在当前位置做标记
        buffer.mark(); // mark = position;

        // 从当前位置读取两个字节并重构成char值
        ch = buffer.getChar();
        System.out.println( ch );
        show(buffer);

        // 判断当前位置到限制位置之间是否存在元素
        if(buffer.hasRemaining()) {
            // 获得当前位置和限制位置之间的元素个数
            int n = buffer.remaining();
            byte[] bytes = new byte[n];
            // 从当前位置读取一批字节到指定的数组中
            buffer.get(bytes);
            show(buffer);
            String str = new String(bytes, StandardCharsets.UTF_8);
            System.out.println( str );
        }

        // 返回到最后一次做标记的位置
        buffer.reset(); // position = mark
        System.out.println( buffer.getChar() );

        System.out.println( buffer );
        // 仅修改相关的变量，但不清除缓冲区已有的数据
        buffer.clear(); // position = 0; limit = capacity; mark = -1;
        System.out.println( buffer );

        System.out.println( buffer.getChar() );

    }

    public static void show(Buffer buffer) {
        System.out.printf("容量(capacity): %d, 限制(limit): %d, 位置(position): %d\n",
                           buffer.capacity(), buffer.limit(), buffer.position() );
    }

}
